package com.comtime.swdevice;

import java.lang.reflect.Method;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;
import java.util.Timer;
import java.util.TimerTask;

import com.comtime.utils.LogUtils;
import com.comtime.utils.ToastUtils;
import com.comtime.utils.Util;

import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothGatt;
import android.bluetooth.BluetoothGattCallback;
import android.bluetooth.BluetoothGattCharacteristic;
import android.bluetooth.BluetoothGattDescriptor;
import android.bluetooth.BluetoothGattService;
import android.content.Context;
import android.os.Handler;
import android.util.Log;

public class SWDevice {
	private final String tagString = "ComtimeSDK";

	/**
	 * the device has been disconnected
	 */
	public final static int DEVICE_STATUS_DISCONNECTED = 0;
	/**
	 * the device is connecting
	 */
	public final static int DEVICE_STATUS_CONNECTING = 1;
	/**
	 * the device has been connected
	 */
	public final static int DEVICE_STATUS_CONNECTED = 2;

	// /**
	// * the device is OADing
	// */
	// public final static int DEVICE_STATUS_OADING = 6;

	public final static int COMMAND_FINDING_PHONE = 11;
	/**
	 * The command from device: device stop find your phone
	 */
	public final static int COMMAND_STOP_FINDING_PHONE = 10;

	/**
	 * The command from device: your phone should stop alarm now
	 */
	public final static int COMMAND_STOP_ALARM = 20;
	/**
	 * The command from device: your phone should start alarm now
	 */
	public final static int COMMAND_START_ALARM = 21;
	/**
	 * The command from device:device is low power
	 */
	public final static int COMMAND_LOW_BATTERY = 71;
	/**
	 * The command from device:device is power off
	 */
	public final static int COMMAND_NULL_BATTERY = 72;
	/**
	 * The command from device:device is power full
	 */
	public final static int COMMAND_FULL_BATTERY = 73;
	/**
	 * The command from device:device tick every minute
	 */
	public final static int COMMAND_REMIND_TICK = 6;

	/**
	 * setting: let the device ring
	 */
	public final static int SETTING_START_RING = 1;
	/**
	 * setting: stop the device ring
	 */
	public final static int SETTING_STOP_RING = 0;
	/**
	 * setting: device alert mode is ring
	 */
	public final static int SETTING_ALERT_MODE_RING = 21;
	/**
	 * setting: device alert mode is vibrate
	 */
	public final static int SETTING_ALERT_MODE_VIBRATE = 22;
	/**
	 * setting: device alert mode is ring and vibrate
	 */
	public final static int SETTING_ALERT_MODE_BOTH = 23;

	/**
	 * setting: turn on the function that notify your phone when wallet is open
	 */
	public final static int SETTING_WALLET_PUSH_ON = 51;
	/**
	 * setting: turn off the function that notify your phone when wallet is open
	 */

	public final static int SETTING_WALLET_PUSH_OFF = 50;
	/**
	 * setting: set the wallet open notification interval 10 seconds
	 */
	public final static int SETTING_WALLET_PUSH_INTERVAL_10S = 85;

	/**
	 * setting: set the wallet open notification interval 60 seconds
	 */
	public final static int SETTING_WALLET_PUSH_INTERVAL_60S = 86;
	/**
	 * setting: set the wallet open notification interval 120 seconds
	 */
	public final static int SETTING_WALLET_PUSH_INTERVAL_120S = 87;

	/**
	 * setting: set the device alert once when disconnect
	 */
	public final static int SETTING_DEVICE_ALERT_TINES_1 = 111;
	/**
	 * setting: set the device alert 3 times when disconnect
	 */
	public final static int SETTING_DEVICE_ALERT_TINES_3 = 113;
	/**
	 * setting:set the device alert 5 times when disconnect
	 */
	public final static int SETTING_DEVICE_ALERT_TINES_5 = 115;

	/**
	 * setting:turn on the function that: the device will sleep automatically if
	 * the device was not connected for 3 days
	 */
	public final static int SETTING_DEVICE_AUTO_SLEEP_ON = 102;
	/**
	 * setting:turn off the function that: the device will sleep automatically
	 * if the device was not connected for 3 days
	 */
	public final static int SETTING_DEVICE_AUTO_SLEEP_OFF = 103;
	/**
	 * setting:turn on the function that: the device will beep every 30 minutes
	 * if the device was not connected
	 */
	public final static int SETTING_DEVICE_BEEP_REMINDER_DISCONNECT_ON = 74;
	/**
	 * setting:turn off the function that: the device will beep every 30 minutes
	 * if the device was not connected
	 */
	public final static int SETTING_DEVICE_BEEP_REMINDER_DISCONNECT_OFF = 75;
	/**
	 * setting:turn on the function that: the device will beep when the wallet
	 * is open during the device not connected
	 */
	public final static int SETTING_WALLET_PUSH_BEEP_REMINDER_DISCONNECT_ON = 72;
	/**
	 * setting:turn off the function that: the device will beep when the wallet
	 * is open during the device not connected
	 */
	public final static int SETTING_WALLET_PUSH_BEEP_REMINDER_DISCONNECT_OFF = 73;
	/**
	 * setting:turn on the anti-lost function that: the device will alert when
	 * it is disconnected
	 */
	public final static int SETTING_ANTI_LOST_ON = 93;
	/**
	 * setting:turn off the anti-lost function that: the device will alert when
	 * it is disconnected
	 */
	public final static int SETTING_ANTI_LOST_OFF = 94;

	public final static int SETTING_InterimNotDisturb_ON = 95;
	/**
	 * setting:turn off the anti-lost function that: the device will alert when
	 * it is disconnected
	 */
	public final static int SETTING_InterimNotDisturb_OFF = 96;

	/**
	 * setting:turn on the function that: the device won't alert even if it is
	 * disconnected during the Not-disturb period
	 */
	public final static int SETTING_NOT_DISTURB_ON = 97;
	/**
	 * setting:turn off the function that: the device won't alert even if it is
	 * disconnected during the Not-disturb period
	 */
	public final static int SETTING_NOT_DISTURB_OFF = 98;

	/**
	 * setting: set the alert distance:far
	 */
	public final static int SETTING_DISTANCE_FAR = 32;
	/**
	 * setting: set the alert distance:near
	 */
	public final static int SETTING_DISTANCE_NEAR = 30;
	/**
	 * setting: device ring mid distence
	 */
	public final static int SETTING_DISTANCE_MID = 31;
	/**
	 * It will prolong the warning delay to 20 seconds
	 */
	public final static int SETTING_REDUCE_UNEXPECTED_WARNING_ON = 104;
	/**
	 * cancel the the 20-seconds warning delay
	 */
	public final static int SETTING_REDUCE_UNEXPECTED_WARNING_OFF = 105;

	/**
	 * 设备寻找手机模式 ：二击
	 */
	public final static int SETTING_DEVICE_FIND_PHONE_TWO = 106;
	/**
	 * 设备寻找手机模式 ：三击
	 */
	public final static int SETTING_DEVICE_FIND_PHONE_THREE = 107;
	/**
	 * set the device alert volume high
	 */
	public final static int SETTING_DEVICE_VOLUME_HIGH = 13;
	/**
	 * set the device alert volume normal
	 */
	public final static int SETTING_DEVICE_VOLUME_NORMAL = 11;

	public final static int SETTING_DEVICE_UPDATE_MAX = 122;
	public final static int SETTING_DEVICE_UPDATE_FAST = 121;
	public final static int SETTING_DEVICE_UPDATE_SLOW = 120;

	private int tag;// 标签，比如设备1 ，设备2，设备3
	private int deviceStatus;
	// 0 未连接状态
	// 1正在连接状态
	// 2已连接状态
	// 3 手机ring device状态
	// 4 device ring 手机状态
	// 5 重连状态

	private BluetoothDevice bluetoothDevice;
	private BluetoothGatt mBluetoothGatt;
	private BluetoothGattCharacteristic batteryChar, nameChar, writeChar,
			keyChar, deviceChar;
	private String deviceVersionName = "";

	private DeviceListener deviceListener;
	private Context context;

	private boolean programming = false;// 正在OAD
	public boolean busy = false;

	private boolean hasOADFunction;

	private ArrayList<BleOperation> bleOperations = new ArrayList<BleOperation>();

	public SWDevice(Context context, int tag) {
		super();
		this.context = context;
		this.tag = tag;
	}

	public SWDevice(Context context, int tag, BluetoothDevice device,
			DeviceListener deviceListener) {
		this.bluetoothDevice = device;
		this.deviceListener = deviceListener;
		this.deviceStatus = DEVICE_STATUS_DISCONNECTED;
		this.tag = tag;
		this.context = context;
	}

	public void setDeviceListener(DeviceListener deviceListener) {
		this.deviceListener = deviceListener;
	}

	/**
	 * set the device tag. you can distinguish between different devices by the
	 * tag
	 * 
	 * @param tag
	 */
	public void setTag(int tag) {
		this.tag = tag;
	}

	// 清除连接信息
	public boolean refreshGattStructure(BluetoothGatt gatt) {
		BluetoothGatt localGatt = gatt;
		try {
			Method localMethod = localGatt.getClass().getMethod("refresh",
					new Class[0]);
			if (localMethod != null) {
				boolean result = ((Boolean) localMethod.invoke(localGatt,
						new Object[0])).booleanValue();
				return result;
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
		return false;
	}

	/**
	 * get the device tag
	 * 
	 * @return the device tag
	 */
	public int getTag() {
		return this.tag;
	}

	/**
	 * 
	 * @return the BluetoothDevice connected
	 */
	public BluetoothDevice getBluetoothDevice() {
		return bluetoothDevice;
	}

	/**
	 * 
	 * @param bluetoothDevice
	 */
	public void setBluetoothDevice(BluetoothDevice bluetoothDevice) {
		this.bluetoothDevice = bluetoothDevice;
	}

	/**
	 * 
	 * @return get device name that in BluetoothGattCharacteristic
	 */
	public String getDeviceVersionName() {
		return deviceVersionName;
	}

	public void myTest() {
		Log.e(tagString, "myTest");
	}

	// public int getConnectionState() {
	// if (mBluetoothGatt != null && bluetoothDevice != null) {
	// int state = ((BluetoothManager) context
	// .getSystemService(Context.BLUETOOTH_SERVICE))
	// .getConnectionState(bluetoothDevice, BluetoothGatt.GATT);
	// if (state == BluetoothGatt.STATE_CONNECTED) {
	// return DEVICE_STATUS_CONNECTED;
	// } else if (state == BluetoothGatt.STATE_DISCONNECTED) {
	// return DEVICE_STATUS_DISCONNECTED;
	// } else if (state == BluetoothGatt.STATE_CONNECTING) {
	// return DEVICE_STATUS_CONNECTING;
	// }
	// } else {
	// return DEVICE_STATUS_DISCONNECTED;
	// }
	// return DEVICE_STATUS_DISCONNECTED;
	// }

	public boolean isProgramming() {
		return programming;
	}

	Handler handler = new Handler();

	public void connectGatt() {

		if (bluetoothDevice != null) {
			if (mBluetoothGatt != null) {

			}
			handler.postDelayed(connectGattRunnable, 30);

		} else {
			Log.e(tagString,
					"the bluetoothDevice is null, please reset the bluetoothDevice");
		}
	}

	Runnable connectGattRunnable = new Runnable() {

		@Override
		public void run() {
			if (bluetoothDevice != null) {
				if (mBluetoothGatt != null) {

				}
				mBluetoothGatt = bluetoothDevice.connectGatt(context, false,
						gattCallback);

			} else {
				Log.e(tagString,
						"the bluetoothDevice is null, please reset the bluetoothDevice");
			}
		}
	};

	public boolean justConnect() {
		if (mBluetoothGatt != null) {
			return mBluetoothGatt.connect();
		}
		return false;
	}

	public void discoveryService() {
		if (mBluetoothGatt != null) {
			mBluetoothGatt.discoverServices();
		}
	}

	/**
	 * cancel the connection with the device
	 */
	public void disconnect() {
		if (mBluetoothGatt != null) {
			mBluetoothGatt.disconnect();
		} else {
			Log.e("ComtimeSDK",
					"disconnect failed,  the mBluetoothGatt  is null ");
		}

	}

	public void reset() {
		batteryChar = null;
		nameChar = null;
		writeChar = null;
		mCharIdentify = null;
		mCharBlock = null;
		bleOperations.clear();

	}

	/**
	 * remove the connection with the device
	 */
	public void remove() {
		if (mBluetoothGatt != null) {
			mBluetoothGatt.close();
			mBluetoothGatt.disconnect();
			mBluetoothGatt = null;
		}
		stopOAD();
		deviceStatus = DEVICE_STATUS_DISCONNECTED;
		deviceVersionName = "";
		bluetoothDevice = null;

		hasOADFunction = false;
		programming = false;
	}

	/**
	 * Descriptor value to read from the remote device
	 * 
	 * @return true, if the read operation was initiated successfully
	 */
	public boolean readRssi() {
		if (mBluetoothGatt != null && isConnected()) {
			return mBluetoothGatt.readRemoteRssi();
		}
		return false;
	}

	/**
	 * read the device name, the result will be on getName
	 */
	public boolean readDeviceName() {
		if (mBluetoothGatt != null) {
			if (nameChar == null) {
				List<BluetoothGattService> list = mBluetoothGatt.getServices();
				for (BluetoothGattService bluetoothGattService : list) {
					if (bluetoothGattService.getUuid().toString()
							.equals(UUIDUtils.NAME_SERVICE_UUID)) {

						for (BluetoothGattCharacteristic charac : bluetoothGattService
								.getCharacteristics()) {
							if (charac.getUuid().toString()
									.equals(UUIDUtils.NAME_CHAR_UUID)) {
								nameChar = charac;
								break;
							}
						}
						break;
					}
				}
				if (nameChar != null) {
					addReadOperation(nameChar);
				} else {
					Log.e(tagString, "nameChar is null");
					return false;
				}
			} else {
				addReadOperation(nameChar);
			}
		}
		return false;
	}

	/**
	 * read the device battery,the result will be on getBattery
	 */
	public boolean readBattery() {
		if (mBluetoothGatt != null) {
			if (batteryChar == null) {
				List<BluetoothGattService> list = mBluetoothGatt.getServices();
				for (BluetoothGattService bluetoothGattService : list) {
					if (bluetoothGattService.getUuid().toString()
							.equals(UUIDUtils.BATTERY_SERVICE_UUID)) {

						for (BluetoothGattCharacteristic charac : bluetoothGattService
								.getCharacteristics()) {
							if (charac.getUuid().toString()
									.equals(UUIDUtils.BATTERY_CHAR_UUID)) {
								batteryChar = charac;
								break;
							}
						}
						break;
					}
				}
				if (batteryChar != null) {
					Log.e(tagString, "readBattery ");
					addReadOperation(batteryChar);
				} else {
					Log.e(tagString, "batteryChar is null");
					return false;
				}
			} else {
				Log.e(tagString, "readBattery ");
				addReadOperation(batteryChar);
			}

		}
		return false;
	}

	/**
	 * start let the device ring
	 */
	public void startRing() {
		if (mBluetoothGatt != null && writeChar != null) {
			sendToDevice(SETTING_START_RING);
		}
	}

	/**
	 * stop the device ring
	 */
	public void stopRing() {
		if (mBluetoothGatt != null && writeChar != null) {
			sendToDevice(SETTING_STOP_RING);
		}
	}

	/**
	 * turn on the anti-lost function
	 */
	public void startAntilost() {
		if (mBluetoothGatt != null && writeChar != null) {
			sendToDevice(SETTING_ANTI_LOST_ON);
		}
	}

	/**
	 * turn off the anti-lost function
	 */
	public void stopAntilost() {
		if (mBluetoothGatt != null && writeChar != null) {
			sendToDevice(SETTING_ANTI_LOST_OFF);
		}
	}

	/**
	 * don't disturb when disconnected
	 */
	public void startNotDisturb() {
		if (mBluetoothGatt != null && writeChar != null) {
			sendToDevice(SETTING_NOT_DISTURB_ON);
		}
	}

	/**
	 * stop not disturb
	 */
	public void stopNotDisturb() {
		if (mBluetoothGatt != null && writeChar != null) {
			sendToDevice(SETTING_NOT_DISTURB_OFF);
		}
	}

	/**
	 * start not disturb interimly
	 */
	public void startInterimNotDisturb() {
		if (mBluetoothGatt != null && writeChar != null) {
			sendToDevice(95);
		}
	}

	/**
	 * stop not disturb interimly
	 */
	public void stopInterimNotDisturb() {
		if (mBluetoothGatt != null && writeChar != null) {
			sendToDevice(96);
		}
	}

	/**
	 * 
	 * @param mode
	 *            SETTING_ALERT_MODE_RING,SETTING_ALERT_MODE_VIBRATE,
	 *            SETTING_ALERT_MODE_BOTH
	 */

	public void setDeviceAlertMode(int mode) {
		if (mBluetoothGatt != null && writeChar != null) {
			if (mode == SETTING_ALERT_MODE_RING
					|| mode == SETTING_ALERT_MODE_VIBRATE
					|| mode == SETTING_ALERT_MODE_BOTH)
				sendToDevice(mode);
		}
	}

	/**
	 * 
	 * @param intervalValue
	 *            SETTING_WALLET_PUSH_INTERVAL_10S;
	 *            SETTING_WALLET_PUSH_INTERVAL_60S
	 *            ;SETTING_WALLET_PUSH_INTERVAL_120S
	 */
	public void setWalletPushInterval(int intervalValue) {
		if (mBluetoothGatt != null && writeChar != null) {
			if (intervalValue == SETTING_WALLET_PUSH_INTERVAL_10S
					|| intervalValue == SETTING_WALLET_PUSH_INTERVAL_60S
					|| intervalValue == SETTING_WALLET_PUSH_INTERVAL_120S)
				sendToDevice(intervalValue);
		}
	}

	/**
	 * 
	 * @param times
	 *            SETTING_DEVICE_ALERT_TINES_1;SETTING_DEVICE_ALERT_TINES_3;
	 *            SETTING_DEVICE_ALERT_TINES_5
	 */
	public void setDeviceAlertTimes(int times) {
		if (mBluetoothGatt != null && writeChar != null) {
			if (times == SETTING_DEVICE_ALERT_TINES_1
					|| times == SETTING_DEVICE_ALERT_TINES_3
					|| times == SETTING_DEVICE_ALERT_TINES_5)
				sendToDevice(times);
		}
	}

	/**
	 * 
	 * @param volume
	 *            SETTING_DEVICE_VOLUME_HIGH;SETTING_DEVICE_VOLUME_NORMAL
	 */
	public void setDeviceVolumn(int volume) {
		if (mBluetoothGatt != null && writeChar != null) {
			if (volume == SETTING_DEVICE_VOLUME_HIGH
					|| volume == SETTING_DEVICE_VOLUME_NORMAL)
				sendToDevice(volume);
		}
	}

	/**
	 * turn on the function that: the device will sleep automatically if the
	 * device was not connected for 3 days
	 */
	public void startAutoSleep() {
		if (mBluetoothGatt != null && writeChar != null) {
			sendToDevice(SETTING_DEVICE_AUTO_SLEEP_ON);
		}
	}

	/**
	 * turn on the function that: the device will sleep automatically if the
	 * device was not connected for 3 days
	 */
	public void stopAutoSleep() {
		if (mBluetoothGatt != null && writeChar != null) {
			sendToDevice(SETTING_DEVICE_AUTO_SLEEP_OFF);
		}
	}

	public void startReduceUnexpectedWarning() {
		if (mBluetoothGatt != null && writeChar != null) {
			sendToDevice(SETTING_REDUCE_UNEXPECTED_WARNING_ON);
		}
	}

	public void stopReduceUnexpectedWarning() {
		if (mBluetoothGatt != null && writeChar != null) {
			sendToDevice(SETTING_REDUCE_UNEXPECTED_WARNING_OFF);
		}
	}

	/**
	 * turn on the function that notify your phone when wallet is open
	 */
	public void startWalletPushFunction() {
		if (mBluetoothGatt != null && writeChar != null) {
			sendToDevice(SETTING_WALLET_PUSH_ON);
		}
	}

	/**
	 * turn off the function that notify your phone when wallet is open
	 */
	public void stopWalletPushFunction() {
		if (mBluetoothGatt != null && writeChar != null) {
			sendToDevice(SETTING_WALLET_PUSH_OFF);
		}
	}

	public void showLog() {
		Log.e(tagString, " 133 bu disconnect");
	}

	/**
	 * 
	 * @param value
	 *            SETTING_DISTANCE_NEAR;SETTING_DISTANCE_FAR
	 */
	public boolean setAlertDistance(int value) {
		Log.e(tagString, " setAlertDistance  11111");
		if (value != SETTING_DISTANCE_FAR && value != SETTING_DISTANCE_NEAR
				&& value != SETTING_DISTANCE_MID) {
			return false;
		}
		Log.e(tagString, " setAlertDistance  22222");

		if (mBluetoothGatt != null) {
			for (BluetoothGattService service : mBluetoothGatt.getServices()) {

				if (service.getUuid().toString()
						.equals(UUIDUtils.WRITE_SERVICE_UUID)) {
					for (BluetoothGattCharacteristic charac : service
							.getCharacteristics()) {
						Log.e(tagString, "charac uuid:"
								+ charac.getUuid().toString());
						if (charac.getUuid().toString()
								.equals(UUIDUtils.WRITE_CHAR_UUID_2A09)) {
							
							addDistanceOperation(charac,Conversion.intToHexStr(value));
						 
						}
					}
				}
			}
		}
		return false;
	}

	public void setDeviceUpdate(int update) {
		if (update != SETTING_DEVICE_UPDATE_MAX
				|| update != SETTING_DEVICE_UPDATE_FAST
				|| update != SETTING_DEVICE_UPDATE_SLOW) {
			return;
		}
		if (mBluetoothGatt != null && writeChar != null) {
			sendToDevice(update);
		}
	}

	/**
	 * get the device is connected or not
	 * 
	 * @return true is connected,false not
	 */
	public boolean isConnected() {
		if (deviceStatus >= 2 && deviceStatus < 5) {
			return true;
		}
		return false;
	}

	/**
	 * clear bluetoothgatt
	 */
	private void close() {
		if (mBluetoothGatt != null) {
			refreshGattStructure(mBluetoothGatt);
			mBluetoothGatt.close();
		}
	}

	private BluetoothGattCallback gattCallback = new BluetoothGattCallback() {

		@Override
		public void onCharacteristicChanged(BluetoothGatt gatt,
				BluetoothGattCharacteristic characteristic) {

			super.onCharacteristicChanged(gatt, characteristic);
			Log.e("ComtimeSDK", " onCharacteristicChanged :"
					+ Bytes2HexString(characteristic.getValue()));
			String uuid = characteristic.getService().getUuid().toString();
			if (uuid.equals(UUIDUtils.DEVICE_SERVICE_UUID)) {
				int value = characteristic.getValue()[0];
				if (value < 0) {// 与钱包打开 回传有关

				} else {
					value = Integer.valueOf(Integer.toHexString(value), 10);
					deviceListener.onGetValue(tag, value, bluetoothDevice);
				}
			} else if (uuid.equals(UUIDUtils.OAD_SERVICE_UUID)) {
				Log.e("ComtimeSDK", " get ver :"
						+ Bytes2HexString(characteristic.getValue()));
				int value = (characteristic.getValue()[1] << 8 & 0xff00)
						| (characteristic.getValue()[0] & 0xff);

				char type = ((value & 1) == 1) ? 'B' : 'A';
				Log.e("ComtimeSDK", "ver:" + value + " type:" + type);
				deviceListener.onGetImageVerAndType(tag, value, type,
						bluetoothDevice);

			} else if (uuid.equals(UUIDUtils.KEY_SERVICE_UUID)) {
				Log.e("ComtimeSDK", " getkey :"
						+ Bytes2HexString(characteristic.getValue()));
				deviceListener.onGetKeyValue(tag, characteristic.getValue(),
						bluetoothDevice);
			}
		}

		@Override
		public void onCharacteristicRead(BluetoothGatt gatt,
				BluetoothGattCharacteristic characteristic, int status) {
			super.onCharacteristicRead(gatt, characteristic, status);
			Log.e("ComtimeSDK", "onCharacteristicRead  " + status);

			if (characteristic.getUuid().toString()
					.equals(UUIDUtils.BATTERY_CHAR_UUID)) {// 获取到电量
				int battery = characteristic.getValue()[0];
				deviceListener.onGetBattery(tag, battery, bluetoothDevice);
			} else if (characteristic.getUuid().toString()
					.equals(UUIDUtils.NAME_CHAR_UUID)) {
				deviceVersionName = new String(characteristic.getValue());
				deviceListener.onGetDeviceName(tag, deviceVersionName,
						bluetoothDevice);
			}
			if (bleOperations.size() > 0) {
				bleOperations.remove(0);
				doNextBleOperation();
			}
		}

		@Override
		public void onCharacteristicWrite(BluetoothGatt gatt,
				BluetoothGattCharacteristic characteristic, int status) {
			super.onCharacteristicWrite(gatt, characteristic, status);

			if (!programming) {//

				if (status == BluetoothGatt.GATT_SUCCESS) {

					if (characteristic.getService().getUuid().toString()
							.equals(UUIDUtils.WRITE_SERVICE_UUID)) {
						int backValue = characteristic.getValue()[0];
						Log.e("ComtimeSDK", "onCharacteristicWrite:" + status
								+ " value :" + backValue);

						deviceListener.onSendSuccess(tag, backValue,
								bluetoothDevice);
					} else if (characteristic.getService().getUuid().toString()
							.equals(UUIDUtils.KEY_SERVICE_UUID)) {
						Log.e(tagString,
								"keyValue onCharacteristicWrite:"
										+ status
										+ " "
										+ Bytes2HexString(characteristic
												.getValue()));
						deviceListener.onKeyValueSendSuccess(tag,
								characteristic.getValue(), bluetoothDevice);
					}
					if (characteristic.getUuid().toString()
							.equals(UUIDUtils.WRITE_CHAR_UUID_2A09)) {
						Log.e(tagString,
								"  WRITE_CHAR_UUID_2A09 onCharacteristicWrite:"
										+ status
										+ " "
										+ Bytes2HexString(characteristic
												.getValue()));
						if (characteristic.getValue()[0] == 0x20) {
//							handler.post(new Runnable() {
//
//								@Override
//								public void run() {
//									// TODO Auto-generated method stub
//									ToastUtils.showToast(context,
//											"2A09 0x20 发送成功", 2000);
//								}
//							});
						} else {
							Log.e(tagString, " 麻痹的");
						}

					}
				}
				if (bleOperations.size() > 0) {
					bleOperations.remove(0);
					doNextBleOperation();
				}
			} else {
				Log.e("ComtimeSDK", "onCharacteristicWrite:" + status);
				if (status == BluetoothGatt.GATT_SUCCESS) {
					busy = false;
					Log.e(tagString, " busy =false ");
				}
			}

		}

		@Override
		public void onConnectionStateChange(BluetoothGatt gatt, int status,
				int newState) {
			super.onConnectionStateChange(gatt, status, newState);
			bleOperations.clear();
			Log.e(tagString, " onConnectionStateChange : "+status +" newState:"+newState);
			if (status == BluetoothGatt.GATT_SUCCESS) {
				if (newState == BluetoothGatt.STATE_CONNECTED) {// 连接成功
					// deviceListener.onConn(tag, bluetoothDevice);

					gatt.discoverServices();// 寻找服务

				} else if (newState == BluetoothGatt.STATE_DISCONNECTED) {// 断开连接
					if (programming) {
						stopOAD();
					}

					deviceStatus = DEVICE_STATUS_DISCONNECTED;
					deviceListener.onDisconnected(tag, bluetoothDevice);
					hasOADFunction = false;
					reset();
					close();
				}
			} else {
				if (programming) {
					stopOAD();
				}
				disconnect();
				reset();
				close();
				deviceStatus = DEVICE_STATUS_DISCONNECTED;
				deviceListener.onDisconnected(tag, bluetoothDevice);
			}
		}

		@Override
		public void onDescriptorRead(BluetoothGatt gatt,
				BluetoothGattDescriptor descriptor, int status) {
			super.onDescriptorRead(gatt, descriptor, status);
		}

		@Override
		public void onDescriptorWrite(BluetoothGatt gatt,
				BluetoothGattDescriptor descriptor, int status) {
			super.onDescriptorWrite(gatt, descriptor, status);
			if (bleOperations.size() > 0) {
				bleOperations.remove(0);
				doNextBleOperation();
			}

			Log.e(tagString, "onDescriptorWrite :"
					+ descriptor.getCharacteristic().getUuid().toString());

			boolean hasNotifyOperation = false;
			for (BleOperation mBleOperation : bleOperations) {
				if (mBleOperation.operationType == OperationType.OperationType_Notify) {
					hasNotifyOperation = true;
				}
			}
			if (!hasNotifyOperation) {
				if (deviceListener != null) {
					deviceListener.onConnected(tag, bluetoothDevice);
				}
			}

		}

		@Override
		public void onReadRemoteRssi(BluetoothGatt gatt, int rssi, int status) {
			super.onReadRemoteRssi(gatt, rssi, status);
			if (status == BluetoothGatt.GATT_SUCCESS) {
				deviceListener.onGetRssi(tag, rssi, bluetoothDevice);
			}
		}

		@Override
		public void onReliableWriteCompleted(BluetoothGatt gatt, int status) {
			super.onReliableWriteCompleted(gatt, status);
		}

		@Override
		public void onServicesDiscovered(BluetoothGatt gatt, int status) {
			super.onServicesDiscovered(gatt, status);
			bleOperations.clear();
			if (status == BluetoothGatt.GATT_SUCCESS) {
				deviceStatus = DEVICE_STATUS_CONNECTED;
				final List<BluetoothGattService> services = gatt.getServices();
				new Thread(new Runnable() {
					@Override
					public void run() {

						boolean found = false;
						for (BluetoothGattService bluetoothGattService : services) {
							Log.e(tagString, "service uuid:"
									+ bluetoothGattService.getUuid().toString());
							for (BluetoothGattCharacteristic charac : bluetoothGattService
									.getCharacteristics()) {
								Log.e(tagString, "  charac uuid:"
										+ charac.getUuid().toString());

								if (charac.getUuid().toString()
										.equals(UUIDUtils.DEVICE_CHAR_UUID)) {
									Log.e(tagString, "find DEVICE_CHAR_UUID");
									deviceChar = charac;
									addNotificationOperation(  deviceChar);

								} else if (charac.getUuid().toString()
										.equals(UUIDUtils.BATTERY_CHAR_UUID)) {
									batteryChar = charac;
									Log.e(tagString, "find batteryChar");
								} else if (charac.getUuid().toString()
										.equals(UUIDUtils.NAME_CHAR_UUID)) {
									nameChar = charac;
									Log.e(tagString, "find nameChar");
								} else if (charac.getUuid().toString()
										.equals(UUIDUtils.WRITE_CHAR_UUID_2A08)) {
									writeChar = charac;
									Log.e(tagString, "find writeChar");

								} else if (charac.getUuid().toString()
										.equals(UUIDUtils.KEY_CHAR_UUID)) {
									Log.e(tagString, "find keyChar");
									keyChar = charac;
									addNotificationOperation ( keyChar);
								}
								found = true;
							}

							if (bluetoothGattService.getUuid().toString()
									.equals(UUIDUtils.OAD_SERVICE_UUID)) {
								List<BluetoothGattCharacteristic> mCharListOad = bluetoothGattService
										.getCharacteristics();
								if (mCharListOad.size() >= 2) {
									mCharIdentify = mCharListOad.get(0);
									mCharBlock = mCharListOad.get(1);
									hasOADFunction = true;
									addNotificationOperation(  mCharIdentify);
								}
							}

						}

						if (!found) {
							disconnect();
						}

					}
				}).start();
			}
		}
	};

	public void sendRTC() { // TODO Auto-generated method stub
		
		
		Calendar calendar=Calendar.getInstance();  //获取当前时间，作为图标的名字
        int year=calendar.get(Calendar.YEAR) ;
        year=year-2000;
        
        int month=calendar.get(Calendar.MONTH)+1 ;
        int day=calendar.get(Calendar.DAY_OF_MONTH) ;
        int hour=calendar.get(Calendar.HOUR_OF_DAY) ;
        int minute=calendar.get(Calendar.MINUTE) ;
        int second=calendar.get(Calendar.SECOND) ;
        
        int week=calendar.get(Calendar.DAY_OF_WEEK) ;//这里获取的周日-周六是 1-7
        
        week=week-1;
        if(week==0){
        	week=7;
        }
        //周一到周日 对应数据： 1-7
        
        String time=year+"-"+month+"-"+day+" "+hour+":"+minute+":"+second+" week:"+week;
        LogUtils.e(tagString, " time:"+time);
        
		
		byte[] values=new byte[10] ;
		values[0]=0x07;
		values[1]=0x09;
		values[2]=0x0A;
		
		
		values[3]=(byte) second;
		values[4]=(byte) minute;
		values[5]=(byte) hour;
		values[6]=(byte) week;
		values[7]=(byte) day;
		values[8]=(byte) month;
		values[9]=(byte) year;
		
		sendToDevice(values);
	}
	private void addNotificationOperation(BluetoothGattCharacteristic characteristic){
		if(!isConnected()) return;
		BleOperation bleOperation = new BleOperation();
		bleOperation.operationType = OperationType.OperationType_Notify;
		bleOperation.bleChar = characteristic;

		bleOperations.add(bleOperation);

		checkNextBleOperation();
	}
	public void addWriteOperation(String value){
		saveDebug("addWriteOperation :"+value);
		
		if(!isConnected())  return;
		
		saveDebug("2222 addWriteOperation :"+value);
		
		BleOperation bleOperation = new BleOperation();
		bleOperation.operationType = OperationType.OperationType_Write;
		bleOperation.bleChar = writeChar;
		bleOperation.value=value;
		bleOperations.add(bleOperation);
		
		checkNextBleOperation();
	}
	
	public void addDistanceOperation(BluetoothGattCharacteristic characteristic, String value){
		saveDebug("addWriteOperation :"+value);
		
		if(!isConnected())  return;
		
		saveDebug("2222 addWriteOperation :"+value);
		
		BleOperation bleOperation = new BleOperation();
		bleOperation.operationType = OperationType.OperationType_Write;
		bleOperation.bleChar = characteristic;
		bleOperation.value=value;
		bleOperations.add(bleOperation);
		
		checkNextBleOperation();
	}
	
	public void addKeyWriteOperation(String value){
		saveDebug("addKeyWriteOperation :"+value);
		
		if(!isConnected())  return;
		
		saveDebug("2222 addWriteOperation :"+value);
		
		BleOperation bleOperation = new BleOperation();
		bleOperation.operationType = OperationType.OperationType_Write;
		bleOperation.bleChar = keyChar;
		bleOperation.value=value;
		bleOperations.add(bleOperation);
		checkNextBleOperation();
	}
	public void addReadOperation(BluetoothGattCharacteristic characteristic){
		if(!isConnected()) return;
		BleOperation bleOperation = new BleOperation();
		bleOperation.operationType = OperationType.OperationType_Read;
		bleOperation.bleChar =characteristic ;

		bleOperations.add(bleOperation);
		
		checkNextBleOperation();
	}

	/**
     * 
     */
	private boolean enableNotification(boolean enable,
			BluetoothGattCharacteristic characteristic) {
		if (mBluetoothGatt == null || characteristic == null)
			return false;
		if (!mBluetoothGatt.setCharacteristicNotification(characteristic,
				enable))
			return false;
		BluetoothGattDescriptor clientConfig = characteristic
				.getDescriptor(UUIDUtils.CCC);
		if (clientConfig == null)
			return false;

		if (enable) {
			clientConfig
					.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
		} else {
			clientConfig
					.setValue(BluetoothGattDescriptor.DISABLE_NOTIFICATION_VALUE);
		}
		return mBluetoothGatt.writeDescriptor(clientConfig);
	}
	
	
	

	public void sendToDevice(int sendValue) {
		if (!isConnected()) {

			Log.e(tagString, "send value fialed, deivce not connected");
			return;
		}
		if (mBluetoothGatt == null) {
			Log.e(tagString, "send value fialed, mBluetoothGatt is null");
			return;
		}
		if (writeChar == null) {
			Log.e(tagString, "send value fialed, writeChar is null");
			return;

		}
		if (programming) {
			Log.e(tagString, "send value fialed, is programming");
			return;
		}
 
		addWriteOperation(Conversion.intToHexStr(sendValue));
		

	}

	public void sendToDevice(byte[] values) {
		if (!isConnected()) {

			Log.e(tagString, "send value fialed, deivce not connected");
			return;
		}
		if (mBluetoothGatt == null) {
			Log.e(tagString, "send value fialed, mBluetoothGatt is null");
			return;
		}
		if (keyChar == null) {
			Log.e(tagString, "send value fialed, keyChar is null");
			return;

		}
		if (programming) {
			Log.e(tagString, "send value fialed, is programming");
			return;
		}

		// writeChar.setValue(sendValue,
		// BluetoothGattCharacteristic.FORMAT_UINT8,
		// 0);
		Log.e("tag", "发送:" + Util.Bytes2HexString(values));


		addKeyWriteOperation(Conversion.Bytes2HexString(values));
	}

	public boolean writeCharacteristic(
			BluetoothGattCharacteristic characteristic, byte[] values,
			boolean needResponse) {

		if (!isConnected()) {

			Log.e(tagString, "writeCharacteristic fialed, deivce not connected");
			return false;
		}
		if (mBluetoothGatt == null) {
			Log.e(tagString,
					"writeCharacteristic fialed, mBluetoothGatt is null");
			return false;
		}
		if (characteristic == null) {
			Log.e(tagString,
					"writeCharacteristic fialed, characteristic is null");
			return false;
		}

		characteristic.setValue(values);
		if (!needResponse) {
			characteristic
					.setWriteType(BluetoothGattCharacteristic.WRITE_TYPE_NO_RESPONSE);
		}
		return mBluetoothGatt.writeCharacteristic(characteristic);

	}

	private boolean writeCharacteristic(
			BluetoothGattCharacteristic characteristic, boolean needResponse) {
		if (!isConnected()) {

			Log.e(tagString,
					"writeCharacteristic   fialed,deivce not connected");
			return false;
		}
		if (mBluetoothGatt == null) {
			Log.e(tagString,
					"writeCharacteristic   fialed,mBluetoothGatt is null");
			return false;
		}
		if (characteristic == null) {
			Log.e(tagString,
					"writeCharacteristic   fialed,characteristic is null");
			return false;
		}

		if (!needResponse) {
			characteristic
					.setWriteType(BluetoothGattCharacteristic.WRITE_TYPE_NO_RESPONSE);
		}
		return mBluetoothGatt.writeCharacteristic(characteristic);

	}

	public void sendKeyValue(byte[] values) {
		if (isConnected() && mBluetoothGatt != null && keyChar != null) {

			Log.e(tagString, "send keyValue:" + Bytes2HexString(values));
			keyChar.setValue(values);
			keyChar.setWriteType(BluetoothGattCharacteristic.WRITE_TYPE_NO_RESPONSE);
			mBluetoothGatt.writeCharacteristic(keyChar);
		} else {
			if (keyChar == null) {
				Log.e(tagString, "keyChar is null");
			}
		}
	}

	private BluetoothGattCharacteristic mCharIdentify, mCharBlock;

	/**
	 * 
	 * @return hasOADfunction or not
	 */
	public boolean hasOADFunction() {
		return hasOADFunction;
	}

	public boolean hasKeyFunction() {
		return keyChar != null;
	}

	/**
	 * if success ,the result will be on DeviceListener.onGetImageVerAndType(int
	 * tag,int ver,char type, BluetoothDevice device);
	 */
	public boolean getImageVerAndType() {
		if (!hasOADFunction()) {
			Log.e("ComtimeSDK", "don't have OAD function");
			return false;
		}

		boolean ok = writeCharacteristic(mCharIdentify, new byte[] { 0 }, false);

		if (ok) {
			ok = writeCharacteristic(mCharIdentify, new byte[] { 1 }, false);
			Log.e("ComtimeSDK", "read ImageVerAndType");
		}
		return ok;
	}

	private int iBytes; // Number of bytes programmed
	private short iBlocks; // Number of blocks programmed
	private short nBlocks; // Total number of blocks
	int MY_INTERVAL = 50;
	private int sleepInterval = 800;

	int PKT_INTERVAL = 20;

	public void setOADInterval(int interval) {
		MY_INTERVAL = interval;
	}

	public void setOADPKT_Interval(int interval) {
		PKT_INTERVAL = interval;
	}

	public void setOADSleep(int interval) {
		sleepInterval = interval;
	}

	/**
	 * start on air download
	 * 
	 * @param imageInfo
	 *            the information you want to update to
	 */
	public List<BluetoothGattService> getServices() {
		if (mBluetoothGatt != null) {
			return mBluetoothGatt.getServices();
		}
		return null;

	}

	private Thread oadThread;

	public void stopOAD() {
		programming = false;
		if (oadThread != null) {
			oadThread.interrupt();
		}
		if (mTimer != null) {
			mTimer.cancel();
		}
	}

	public int startOAD(byte[] bytes) {
		final ImageInfo imageInfo = new ImageInfo();
		imageInfo.len = Conversion.buildUint16(bytes[7], bytes[6]);
		imageInfo.fileBytes = bytes;
		imageInfo.ver = Conversion.getImageVer(imageInfo.fileBytes);
		imageInfo.imgType = ((imageInfo.ver & 1) == 1) ? 'B' : 'A';

		Log.e(tagString, "startOAD imageInfo.len:" + imageInfo.len +" ver:"+imageInfo.ver  +" imgType:"+imageInfo.imgType);
		if (!hasOADFunction()) {
			Log.i("ComtimeSDK", "don't have OAD function");
			return 0;
		}

		final int OAD_BLOCK_SIZE = 16;
		final int HAL_FLASH_WORD_SIZE = 4;
		final int OAD_BUFFER_SIZE = 2 + OAD_BLOCK_SIZE;
		final int OAD_IMG_HDR_SIZE = 8;

		programming = true;
		byte[] buf = new byte[OAD_IMG_HDR_SIZE + 2 + 2];
		buf[0] = Conversion.loUint16(imageInfo.ver);
		buf[1] = Conversion.hiUint16(imageInfo.ver);
		buf[2] = Conversion.loUint16((short) imageInfo.len);
		buf[3] = Conversion.hiUint16((short) imageInfo.len);
		System.arraycopy(imageInfo.uid, 0, buf, 4, 4);
		// Send image notification
		mCharIdentify.setValue(buf);
		writeCharacteristic(mCharIdentify, true);

		iBytes = 0;
		iBlocks = 0;
		nBlocks = 0;

		nBlocks = (short) (imageInfo.len / (OAD_BLOCK_SIZE / HAL_FLASH_WORD_SIZE));

		if (oadThread != null) {
			oadThread.interrupt();
		}

		oadThread = new Thread(new Runnable() {

			@Override
			public void run() {
				while (programming) {
					// Log.e(tagString, "read to write busy:" + busy);

					if (!busy) {
						if (iBlocks < nBlocks) {
							byte[] mOadBuffer = new byte[OAD_BUFFER_SIZE];
							mOadBuffer[0] = Conversion.loUint16(iBlocks);
							mOadBuffer[1] = Conversion.hiUint16(iBlocks);
							System.arraycopy(imageInfo.fileBytes, iBytes,
									mOadBuffer, 2, OAD_BLOCK_SIZE);
							mCharBlock.setValue(mOadBuffer);
							// Log.e(tagString,
							// "================ write ==========");
							busy = true;
							boolean success = writeCharacteristic(mCharBlock,
									false);
							if (success) {
								iBlocks++;
								Log.e(tagString, "write success:" + iBlocks
										+ " nBlocks:" + nBlocks);
								iBytes += OAD_BLOCK_SIZE;
								if ((iBlocks % 5) == 0) {
									float progress = (float) (iBlocks * 1.0 / nBlocks);

									int secondLeft = (nBlocks - iBlocks)
											* MY_INTERVAL / 1000;

									deviceListener.onGetOADProgress(tag,
											progress, secondLeft);
								}
							} else {
								// Log.e(tagString, "write unsuccess!!!");
								try {
									Thread.sleep(sleepInterval);

								} catch (InterruptedException e) {

								}
								writeCharacteristic(mCharBlock, false);
								try {
									Thread.sleep(MY_INTERVAL);
								} catch (InterruptedException e) {

								}
							}
						} else {

							deviceListener.onGetOADProgress(tag, 1, 0);
							programming = false;

						}
						try {
							Thread.sleep(MY_INTERVAL);

						} catch (InterruptedException e) {

						}
					} else {
						Log.e(tagString, "Thread.sleep(800)");
						try {
							Thread.sleep(sleepInterval);

						} catch (InterruptedException e) {

						}
						writeCharacteristic(mCharBlock, false);
						try {
							Thread.sleep(MY_INTERVAL);
						} catch (InterruptedException e) {
						}
					}
				}
			}
		});
		oadThread.start();
		int totalTime = nBlocks * (MY_INTERVAL) / 1000;

		return totalTime;
	}

	Timer mTimer;

	public int startOAD2(byte[] bytes) {

		final ImageInfo imageInfo = new ImageInfo();
		imageInfo.len = Conversion.buildUint16(bytes[7], bytes[6]);
		imageInfo.fileBytes = bytes;
		imageInfo.ver = Conversion.getImageVer(imageInfo.fileBytes);
		imageInfo.imgType = ((imageInfo.ver & 1) == 1) ? 'B' : 'A';

		Log.i(tagString, "startOAD imageInfo.len:" + imageInfo.len);
		if (!hasOADFunction()) {

			Log.i("ComtimeSDK", "don't have OAD function");
			return 0;
		}

		if (mTimer != null) {
			mTimer.cancel();
		}
		final int OAD_BLOCK_SIZE = 16;
		final int HAL_FLASH_WORD_SIZE = 4;
		final int OAD_BUFFER_SIZE = 2 + OAD_BLOCK_SIZE;
		final int OAD_IMG_HDR_SIZE = 8;

		programming = true;
		byte[] buf = new byte[OAD_IMG_HDR_SIZE + 2 + 2];
		buf[0] = Conversion.loUint16(imageInfo.ver);
		buf[1] = Conversion.hiUint16(imageInfo.ver);
		buf[2] = Conversion.loUint16((short) imageInfo.len);
		buf[3] = Conversion.hiUint16((short) imageInfo.len);
		System.arraycopy(imageInfo.uid, 0, buf, 4, 4);
		// Send image notification
		mCharIdentify.setValue(buf);
		writeCharacteristic(mCharIdentify, true);

		iBytes = 0;
		iBlocks = 0;
		nBlocks = 0;

		mTimer = new Timer();

		nBlocks = (short) (imageInfo.len / (OAD_BLOCK_SIZE / HAL_FLASH_WORD_SIZE));
		final TimerTask timerTask = new TimerTask() {

			@Override
			public void run() {
				try {
					Thread.sleep(MY_INTERVAL);
				} catch (InterruptedException e1) {
					e1.printStackTrace();

				}
				if (programming) {
					// Log.e(tagString, "read to write busy:" + busy);
					if (!busy) {
						if (iBlocks < nBlocks) {
							byte[] mOadBuffer = new byte[OAD_BUFFER_SIZE];
							mOadBuffer[0] = Conversion.loUint16(iBlocks);
							mOadBuffer[1] = Conversion.hiUint16(iBlocks);
							System.arraycopy(imageInfo.fileBytes, iBytes,
									mOadBuffer, 2, OAD_BLOCK_SIZE);
							mCharBlock.setValue(mOadBuffer);
							busy = true;
							boolean success = writeCharacteristic(mCharBlock,
									false);

							if (success) {
								iBlocks++;
								// Log.e(tagString, "write success:" + iBlocks
								// + " nBlocks:" + nBlocks);
								iBytes += OAD_BLOCK_SIZE;
								if ((iBlocks % 5) == 0) {
									int secondLeft = (nBlocks - iBlocks)
											* (MY_INTERVAL + PKT_INTERVAL)
											/ 1000;
									deviceListener.onGetOADProgress(tag,
											(float) (iBlocks * 1.0 / nBlocks),
											secondLeft);
								}
							} else {
								// Log.e(tagString, "write unsuccess!!!");
								try {
									Thread.sleep(sleepInterval);
								} catch (InterruptedException e) {
									// TODO Auto-generated catch block
									e.printStackTrace();
								}
								writeCharacteristic(mCharBlock, false);
								try {
									Thread.sleep(PKT_INTERVAL);
								} catch (InterruptedException e) {
									// TODO Auto-generated catch block
									e.printStackTrace();
								}
							}
						} else {// 下发完成
							deviceListener.onGetOADProgress(tag, 1, 0);
							programming = false;
							mTimer.cancel();
						}
					} else {
						try {
							Log.e(tagString, "Thread.sleep(800)");
							Thread.sleep(sleepInterval);
						} catch (InterruptedException e) {
							e.printStackTrace();
						}
						writeCharacteristic(mCharBlock, false);
					}
				}
			}
		};
		mTimer.scheduleAtFixedRate(timerTask, 3000, PKT_INTERVAL);

		int totalTime = nBlocks * (MY_INTERVAL + PKT_INTERVAL) / 1000;

		return totalTime;

	}

	/**
	 * before startOAD,you need do this
	 */
	public void startOADMode() {
		if (mBluetoothGatt != null && writeChar != null) {
			sendToDevice(101);
		}
	}

	private final byte[] hex = "0123456789ABCDEF".getBytes();

	// 从字节数组到十六进制字符串转换
	private String Bytes2HexString(byte[] b) {
		byte[] buff = new byte[2 * b.length];
		for (int i = 0; i < b.length; i++) {
			buff[2 * i] = hex[(b[i] >> 4) & 0x0f];
			buff[2 * i + 1] = hex[b[i] & 0x0f];
		}
		return new String(buff);
	}

	private boolean checkIsSamsung() {
		String brand = android.os.Build.BRAND;
		Log.e("", " brand:" + brand);
		if (brand.toLowerCase().equals("samsung")) {
			return true;
		}
		return false;
	}

	private boolean readCharacteristic(
			BluetoothGattCharacteristic characteristic) {
		if (isConnected() && mBluetoothGatt != null && characteristic != null) {
			return mBluetoothGatt.readCharacteristic(characteristic);
		}
		return false;
	}

	private boolean writeCharacteristic(
			BluetoothGattCharacteristic characteristic, byte[] values) {

		if (isConnected() && mBluetoothGatt != null) {
			characteristic.setValue(values);
			Log.e(tagString,
					" writeCharacteristic:"
							+ Conversion.Bytes2HexString(values));
			boolean b = mBluetoothGatt.writeCharacteristic(characteristic);
			return b;
		}
		return false;
	}

	public class BleOperation {
		public String value;
		public BluetoothGattCharacteristic bleChar;

		public OperationType operationType;

	}

	public enum OperationType {
		OperationType_Read, OperationType_Notify, OperationType_Write
	};

	private void checkNextBleOperation() {
		if (bleOperations.size() == 1) {
			BleOperation bleOperation = bleOperations.get(0);

			doBleOperation(bleOperation);

		}
	}

	private void doNextBleOperation() {
		if (bleOperations.size() > 0) {
			BleOperation bleOperation = bleOperations.get(0);

			doBleOperation(bleOperation);
		}
	}

	private void doBleOperation(BleOperation bleOperation) {

		saveDebug(" doBleOperation");

		if (!isConnected()) {
			saveDebug(" doBleOperation :isConnected false");
			return;
		}

		switch (bleOperation.operationType) {
		case OperationType_Read:
			Log.e(tagString, " read:"
					+ bleOperation.bleChar.getUuid().toString());

			saveDebug(" read:" + bleOperation.bleChar.getUuid().toString());
			readCharacteristic(bleOperation.bleChar);

			break;
		case OperationType_Notify:
			Log.e(tagString, " enableNotification:"
					+ bleOperation.bleChar.getUuid().toString());
			saveDebug(" enableNotification:"
					+ bleOperation.bleChar.getUuid().toString());
			enableNotification(true, bleOperation.bleChar);
			break;
		case OperationType_Write:

			byte[] values = Conversion.hexStringToBytes(bleOperation.value);
			Log.e(tagString, " write:" + bleOperation.value);

			saveDebug(" write:" + bleOperation.value);
			writeCharacteristic(bleOperation.bleChar, values);
			break;
		default:
			break;
		}

		handler.removeCallbacks(operationOverTimeRunnable);
		handler.postDelayed(operationOverTimeRunnable, overTime);
	}

	int overTime = 3000;

	private Runnable operationOverTimeRunnable = new Runnable() {

		@Override
		public void run() {
			if (bleOperations.size() > 0) {
				bleOperations.remove(0);
				doNextBleOperation();
			}
		}
	};

	public static void saveDebug(String content) {

		// saveFile(formatTimeYMDHMSF(System.currentTimeMillis())+" "+content+"\n",
		// null,"debug.txt");

	}

	public static String formatTimeYMDHMSF(long time) {

		Timestamp ts = new Timestamp(time);

		return ts.toString();
	}
}
